home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld Secrets (4th Edition)
/
Mac Secrets CD 4th Ed.toast
/
Apple Advanced Technologies
/
Apple Speech Technologies 1.5
/
PlainTalk Developer Info
/
Speech Recognition Manager SDK
/
SR Sample Code
/
Speakable Items Example
/
Sources
/
Main.c
next >
Wrap
Text File
|
1996-03-18
|
19KB
|
678 lines
/*****************************************************************************/
#include "SpeechRecognition.h"
#include "GestaltEqu.h"
#include "Quickdraw.h"
#include "Dialogs.h"
#include "Fonts.h"
#include "AppleEvents.h"
#include "string.h"
#include "Speech.h"
#include <Packages.h>
#include "SpeakableItems.h"
// Comment following out, and set SIZE background-only bit to make faceless version
#define __HAS_UI__
//#define __USE_CALLBACKS__
/*****************************************************************************/
/* Prototypes and globals */
OSErr InitStuff (void);
OSErr InitAndStartSpeechRecognition (void);
void MainLoop (void);
void SayDateOrTime (Boolean date);
#ifdef __HAS_UI__
void HandleMouseDown (EventRecord *theEvent);
void HandleUpdate (EventRecord *theEvent);
void HandleMenuSelect (long menuChoice);
#endif
void CleanupStuff (void);
void CleanupSpeechRecognitionStuff (void);
OSErr MakeALanguageModel (SRLanguageModel *lm);
pascal OSErr HandleQuitAE (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
pascal OSErr DummyAEHandler (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
void ProcessResult (OSErr origStatus, SRRecognitionResult recResult);
#ifdef __USE_CALLBACKS__
pascal void MyNotificationCallBack (SRCallBackStruct *param);
#else
pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
pascal OSErr HandleSpeechBeginningAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
#endif
#ifdef __HAS_UI__
void DisplayString (Str255 str);
#endif
#ifdef __HAS_UI__
#define kAppleMenu 1
#define kFileMenu 2
#define kFirstMenu kAppleMenu
#define kLastMenu kFileMenu
DialogPtr gDialog;
MenuHandle gMenuHandles[kLastMenu];
#endif
SRRecognitionSystem gSystem = 0;
SRRecognizer gRecognizer = 0;
SRLanguageModel gTopLM = 0;
SRLanguageModel gSIModel = 0; /* For SpeakableItems */
Boolean gFinished;
Str255 gLastStr;
SRCallBackStruct gCallBackInfo;
#define kTopLMRefCon 10000
#define kQuitSpeakableItems 10002
#define kWhatTimeIsIt 10004
#define kWhatDayIsIt 10006
#define kSimpleStrsID 500
#define kQuitStr 1
#define kWhatTimeIsItStr 2
#define kWhatDayIsItStr 3
/*****************************************************************************/
void main (void)
{
OSErr status = InitStuff ();
if (!status) {
MainLoop ();
CleanupStuff ();
}
}
/*****************************************************************************/
/* main is the entry point to his program. */
OSErr InitStuff (void)
{
OSErr status = noErr;
Rect rBounds;
GrafPtr oldPort;
SRLanguageObjectFlags autoFin = kSRNoFinishing;
MenuHandle menuH;
short i;
/* Adjust heap */
#ifdef __HAS_UI__
MaxApplZone();
MoreMasters();
MoreMasters();
#endif
/* Init toolboxes */
InitGraf(&qd.thePort);
#ifdef __HAS_UI__
InitFonts();
FlushEvents(everyEvent,0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0);
InitCursor();
#endif
#ifdef __HAS_UI__
for (i = kFirstMenu; i <= kLastMenu; i++) {
menuH = GetMenu(i);
gMenuHandles[i-1] = menuH;
if (menuH) InsertMenu (menuH, 0);
}
menuH = gMenuHandles[kAppleMenu-1];
if (menuH) AddResMenu(menuH,'DRVR');
DrawMenuBar();
/* Make a dialog in which we'll display results */
SetRect (&rBounds, 50,50,450,150);
gDialog = NewDialog(NULL,&rBounds,"\p",true,noGrowDocProc,(WindowPtr)-1,true,0,NULL);
if (!gDialog)
status = -1;
#endif
if (!status)
status = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
NewAEEventHandlerProc (DummyAEHandler), 0, false);
if (!status)
status = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
NewAEEventHandlerProc (DummyAEHandler), 0, false);
if (!status)
status = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
NewAEEventHandlerProc (DummyAEHandler), 0, false);
if (!status)
status = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
NewAEEventHandlerProc (HandleQuitAE), 0, false);
if (!status)
status = InitAndStartSpeechRecognition ();
if (!status)
gFinished = false;
else
gFinished = true;
}
/*****************************************************************************/
/* This routine initializes speech recognition, installs an AppleEvent handler
to handle result notifications from the Speech Recognition Toolbox, calls
another routine to build a simple language model (which specifies a few
phrases a user can say), makes that language model active by calling
SRSetLanguageModel, and starts the recognizer listening. A more realistic
application would have more complicated language models (perhaps having
different language models for different contexts -- using SRSetLanguageModel
to make the appropriate one active), or would use the language model
manipulation routines in the Speech Recognition Toolbox to change the
active language model as the program was used to reflect what the user
might say in any given situation.
*/
OSErr InitAndStartSpeechRecognition ()
{
OSErr status;
long attributes;
Boolean fgOnly = false;
SRCallBackParam callBackPB;
long notifFlags = kSRNotifyRecognitionBeginning | kSRNotifyRecognitionDone;
#ifdef __HAS_UI__
/* The SROpenRecognitionSystem loads lots of data and takes a few
seconds, so display a message indicating this will take a moment.
This would be a good place to show the watch cursor as well. */
DisplayString ("\pStarting up...");
#endif
/* Make sure SpeechRecognition Toolbox is available */
status = Gestalt (gestaltSpeechRecognitionVersion, &attributes);
/* Open a SRRecognitionSystem */
if (!status)
status = SROpenRecognitionSystem (&gSystem, kSRDefaultRecognitionSystemID);
/* Create a recognizer with default speech source -- e.g. the desktop microphone */
if (!status)
status = SRNewRecognizer (gSystem, &gRecognizer, kSRDefaultSpeechSource);
if (!status)
status = SRSetProperty (gRecognizer, kSRForegroundOnly, &fgOnly, sizeof(fgOnly));
if (!status)
status = SRSetProperty (gRecognizer, kSRNotificationParam, ¬ifFlags, sizeof(notifFlags));
#ifdef __USE_CALLBACKS__
/* Install call-back */
if (!status) {
callBackPB.callBack = NewSRCallBackProc (MyNotificationCallBack);
callBackPB.param = &gCallBackInfo;
status = SRSetProperty (gRecognizer, kSRCallBackParam, &callBackPB, sizeof (callBackPB));
}
#else
/* Install an AppleEvent handler so recognizer can send us recognition results. */
if (!status)
status = AEInstallEventHandler(kAESpeechSuite, kAESpeechDone,
NewAEEventHandlerProc (HandleSpeechDoneAppleEvent), 0, false);
if (!status)
status = AEInstallEventHandler(kAESpeechSuite, kAESpeechDetected,
NewAEEventHandlerProc (HandleSpeechBeginningAppleEvent), 0, false);
#endif
/* For this example, we will just make one language model,
make it active, and start listening. */
/* Make a simple language model (LM) */
if (!status)
status = MakeALanguageModel (&gTopLM);
/* Use this LM in recognition */
if (!status)
status = SRSetLanguageModel (gRecognizer, gTopLM);
/* Have the recognizer start processing sound */
if (!status)
status = SRStartListening (gRecognizer);
/* Initialize Speakable Items unit and get an LM representing
the speakable items, and add it to our top level LM. */
if (!status)
status = SIInitSpeakableItems (gSystem, &gSIModel);
if (!status && gSIModel)
status = SRAddLanguageObject (gTopLM, gSIModel);
#ifdef __HAS_UI__
if (!status)
DisplayString ("\pReady");
else
// Couldn't run for some reason. Perhaps there is no 'Speakable Items' folder in the 'Apple Menu Items' folder,
// or perhaps Speech Recognition extension is not installed.
DisplayString ("\pSorry, Can't run. See trouble shooting notes.");
#endif
return status;
}
/*****************************************************************************/
void MainLoop ()
{
Boolean gotEvent;
EventRecord event;
DialogPtr theDialog;
short itemHit;
long sleepTime;
char ch;
/* Here's our overly-simple main event loop */
/* We quit if mouse is clicked in window, */
/* or if any key is clicked. */
/* We also dispatch AppleEvents. */
while (!gFinished) {
if (gFinished) sleepTime = 1; else sleepTime = 0xFFFFFFFF;
gotEvent = WaitNextEvent(everyEvent, &event, sleepTime, NULL);
if (gotEvent) {
switch (event.what) {
#ifdef __HAS_UI__
case mouseDown :
HandleMouseDown (&event);
break;
case keyDown :
ch = event.message & charCodeMask;
if (event.modifiers & cmdKey)
HandleMenuSelect (MenuKey(ch));
break;
case updateEvt :
HandleUpdate (&event);
break;
#endif
case kHighLevelEvent :
AEProcessAppleEvent(&event);
break;
default :
break;
}
}
#ifdef __HAS_UI__
if (IsDialogEvent(&event))
DialogSelect(&event, &theDialog, &itemHit);
#endif
if (!gFinished)
SIUpdateSpeakableItems (gSystem, gSIModel);
}
}
/*****************************************************************************/
#ifdef __HAS_UI__
void HandleMouseDown (EventRecord *theEvent)
{
WindowPtr theWindow;
short inWhatPart = FindWindow (theEvent->where, &theWindow);
Point pt = theEvent->where;
GrafPtr oldPort;
Rect rct;
switch (inWhatPart) {
case inSysWindow :
SystemClick (theEvent, theWindow);
break;
case inContent:
break;
case inMenuBar :
HandleMenuSelect (MenuSelect(theEvent->where));
break;
case inDrag :
rct = qd.screenBits.bounds;
InsetRect (&rct, 20, 20);
DragWindow (theWindow, pt, &rct);
break;
case inGoAway:
if (TrackGoAway (theWindow, pt))
gFinished = true;
break;
default :
break;
}
HiliteMenu (0);
}
#endif
/*****************************************************************************/
#ifdef __HAS_UI__
void HandleUpdate (EventRecord *theEvent)
{
DisplayString (gLastStr);
}
#endif
/*****************************************************************************/
#ifdef __HAS_UI__
void HandleMenuSelect (long menuChoice)
{
short itemNum;
Str255 daName;
GrafPtr ourPort;
itemNum = LoWord(menuChoice);
switch (HiWord(menuChoice)) {
case kAppleMenu :
GetItem (gMenuHandles[kAppleMenu-1], itemNum, daName);
GetPort (&ourPort);
OpenDeskAcc (daName);
SetPort (ourPort);
break;
case kFileMenu :
// all we've got is quit
gFinished = true;
break;
default :
break;
}
}
#endif
/*****************************************************************************/
void CleanupStuff ()
{
CleanupSpeechRecognitionStuff ();
#ifdef __HAS_UI__
if (gDialog)
DisposeDialog (gDialog);
#endif
}
/*****************************************************************************/
void CleanupSpeechRecognitionStuff ()
{
OSErr status;
if (gTopLM)
status = SRReleaseObject (gTopLM);
if (gSIModel)
status = SRReleaseObject (gSIModel);
if (gRecognizer) {
status = SRStopListening (gRecognizer); /* stop processing incoming sound */
status = SRReleaseObject (gRecognizer); /* balance SRNewRecognizer call */
}
if (gSystem)
status = SRCloseRecognitionSystem (gSystem); /* balance SROpenRecognitionSystem call */
}
/*****************************************************************************/
OSErr MakeALanguageModel (SRLanguageModel *model)
{
const char *lmName = "<Sample LM>";
long refCon = kTopLMRefCon;
Str255 str;
OSErr status;
SRLanguageModel newModel;
/* make a simple language model (LM) */
status = SRNewLanguageModel (gSystem, &newModel, lmName, strlen (lmName));
/* set its refcon */
if (!status)
status = SRSetProperty (newModel, kSRRefCon, &refCon, sizeof(refCon));
/* add some items to the top level LM */
if (!status) {
GetIndString(str, kSimpleStrsID, kQuitStr);
status = SRAddText (newModel, str+1, str[0], kQuitSpeakableItems);
GetIndString(str, kSimpleStrsID, kWhatTimeIsItStr);
status = SRAddText (newModel, str+1, str[0], kWhatTimeIsIt);
GetIndString(str, kSimpleStrsID, kWhatDayIsItStr);
status = SRAddText (newModel, str+1, str[0], kWhatDayIsIt);
}
/* return new LM */
if (!status)
*model = newModel;
return status;
}
/*****************************************************************************/
/*****************************************************************************/
pascal OSErr DummyAEHandler (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
{
return noErr;
}
/*****************************************************************************/
pascal OSErr HandleQuitAE (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
{
gFinished = true;
return noErr;
}
/*****************************************************************************/
#ifdef __USE_CALLBACKS__
pascal void MyNotificationCallBack (SRCallBackStruct *param)
{
OSErr status = param->status;
SRRecognitionResult recResult = 0;
// Handle speech-done
if (param->what & kSRNotifyRecognitionDone) {
if (!status)
recResult = (SRRecognitionResult)(param->message);
ProcessResult (status, recResult);
}
}
#else
/*****************************************************************************/
/* Here's an AppleEvent handler for handling the kAESpeechDone event of the
kAESpeechSuite -- i.e. the event indicating a recognition attempt was made.
The keySRSpeechStatus parameter gives the status of the recognition. If it
is noErr, then the keySRSpeechResult parameter gives a SRRecognitionResult with the
various representations of the words the user spoke.
*/
pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
{
long actualSize;
DescType actualType;
OSErr status = 0;
OSErr recStatus = 0;
SRRecognitionResult recResult = 0;
/* Get status */
status = AEGetParamPtr(theAEevt,keySRSpeechStatus,typeShortInteger,
&actualType, (Ptr)&recStatus, sizeof(status), &actualSize);
/* Get result */
if (!status && !recStatus)
status = AEGetParamPtr(theAEevt,keySRSpeechResult,typeSRSpeechResult,
&actualType, (Ptr)&recResult, sizeof(SRRecognitionResult), &actualSize);
/* Process result */
if (!status)
status = recStatus;
ProcessResult (status, recResult);
return status;
}
/*****************************************************************************/
/* AppleEvent handler for kAESpeechDetected event of kAESpeechSuite -- the
event indicating that recognition of an utterance is ready to begin. We
are sent this event because we requested kSRNotifyRecognitionBeginning notification
as well as kSRNotifyRecognitionDone notification. (See InitAndStartSpeechRecognition
routine above, where we set the kSRNotificationParam property of our SRRecognizer.)
*/
pascal OSErr HandleSpeechBeginningAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
{
long actualSize;
DescType actualType;
OSErr status = 0, recStatus = 0;
SRRecognizer rec;
/* Get status */
status = AEGetParamPtr(theAEevt,keySRSpeechStatus,typeShortInteger,
&actualType, (Ptr)&recStatus, sizeof(status), &actualSize);
/* Get SRRecognizer */
if (!status && !recStatus)
status = AEGetParamPtr(theAEevt,keySRRecognizer,typeSRRecognizer,
&actualType, (Ptr)&rec, sizeof(SRRecognizer), &actualSize);
/* Tell SRRecognizer to proceed with recognition attempt */
if (!status && !recStatus && rec)
SRContinueRecognition (rec);
}
#endif /* __USE_CALLBACKS__ */
/*****************************************************************************/
void ProcessResult (OSErr origStatus, SRRecognitionResult recResult)
{
OSErr status = origStatus;
Str255 str;
Size len;
SRLanguageModel resultLM, subLM;
unsigned long refCon;
if (!status && recResult) {
len = sizeof(resultLM);
status = SRGetProperty (recResult, kSRLanguageModelFormat, &resultLM, &len);
if (!status) {
len = sizeof(refCon);
status = SRGetProperty (resultLM, kSRRefCon, &refCon, &len);
// if it's a valid result form our top-level LM,
// then parse and process its elements
if (!status && refCon == kTopLMRefCon) {
// TopLM should have one sub element
status = SRGetIndexedItem (resultLM, &subLM, 0);
if (!status) {
len = sizeof(refCon);
status = SRGetProperty (subLM, kSRRefCon, &refCon, &len);
if (!status) {
// if subLM is from speakable items unit,
// pass it on to that unit to handle it
if (refCon == kSIModelRefCon)
SIProcessResult (subLM);
// else if it's our "quit speakable items" item, quit
// (alternatively, we could another routine to parse
// subLM, just like we call SIProcessResult above, to
// handle the quit sub-item and any other sub-items)
else if (refCon == kQuitSpeakableItems) {
gFinished = true;
#ifdef __HAS_UI__
DisplayString ("\pGoodbye.");
#endif
SpeakString ("\pGoodbye.");
}
else if (refCon == kWhatTimeIsIt)
SayDateOrTime (false);
else if (refCon == kWhatDayIsIt)
SayDateOrTime (true);
}
// release subelement when done with it
SRReleaseObject (subLM);
}
}
// release resultLM fetched above when done with it
SRReleaseObject (resultLM);
}
}
#ifdef __HAS_UI__
// display error conditions
if (status == kSRRecognitionDone)
// no problem. recognizer just didn't recognize
// one of the phrases for which we were listening.
DisplayString ("\p...");
else if (status == kSROutOfMemory)
// ouch! we don't have enough free (system heap) memory to process
// the utterence. speech recognition will not work until more memory
// is available. it might make sense to set gFinished to true to quit,
// since we can't do anything (or at least notify the user what to do)
DisplayString ("\pOut of system memory.");
else if (status)
DisplayString ("\pRecognition error");
#endif
// Release SRRecognitionResult since we are done with it!!!
// The toolbox has given us a reference to this object, and
// assumes we are still using it until we call SRReleaseObject
// with it.
if (!origStatus) SRReleaseObject (recResult);
}
/*****************************************************************************/
void SayDateOrTime (Boolean date)
{
unsigned long secs;
Str255 str;
GetDateTime(&secs);
if (!date)
IUTimeString(secs, false, str);
else
IUDateString(secs, longDate, str);
#ifdef __HAS_UI__
// Display string
DisplayString (str);
#endif
// Call text-to-speech routine to have speech synthesizer speak string
SpeakString (str);
}
/*****************************************************************************/
#ifdef __HAS_UI__
void DisplayString (Str255 str)
{
GrafPtr oldPort;
Rect theRect;
memcpy (gLastStr, str, str[0]+1);
GetPort (&oldPort);
SetPort (gDialog);
theRect = ((GrafPtr)gDialog)->portRect;
theRect.bottom = theRect.bottom-30;
EraseRect(&theRect);
TextSize (12);
MoveTo (40,30);
DrawString (str);
SetPort (oldPort);
}
#endif
/*****************************************************************************/